package com.ruoyi.until;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.rabbitmq.client.Channel;
import com.ruoyi.pojo.Coupon;
import com.ruoyi.pojo.Log;
import com.ruoyi.pojo.User;
import com.ruoyi.service.ActivitiesService;
import com.ruoyi.service.CouponService;
import com.ruoyi.service.LogService;
import com.ruoyi.service.UserService;
import io.lettuce.core.RedisException;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
public class RabbitmqUtil {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ActivitiesService activitiesService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private UserService userService;

    @Autowired
    private LogService logService;

    @RabbitListener(queues = "CouponQueue")
    public void send(String str, Channel channel, Message message) throws IOException {

        System.out.println("接收到消息：" + str);

        try {
            String data = stringRedisTemplate.opsForValue().get(str);

            if (StringUtils.isEmpty(data)){
                System.out.println("已经消费了");
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            }

            HashMap<String, Object> hashMap =  JSONObject.parseObject(data,HashMap.class);
            String couponName = (String) hashMap.get("couponName");
            String userName = (String) hashMap.get("userName");
            R r = seckill(couponName, userName);
            if (r.getCode()==200){
                stringRedisTemplate.delete(str);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }else {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public R seckill(String couponName, String userName) {
        RLock lock = redissonClient.getLock("couponName:"+couponName);
        try {
            // 获取锁，最多等待10秒，锁定5秒
            if (lock.tryLock(10, 5, TimeUnit.SECONDS)) {
                // 进行秒杀操作
                R r = havCoupon(couponName, userName);
                return r;
            } else {
                System.out.println("无法获取锁，秒杀失败");
                return R.error("无法获取锁，秒杀失败");
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("线程中断，秒杀失败");
        } catch (RedisException e) {
            System.out.println("Redis 错误，秒杀失败");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return R.ok();
    }

    public R havCoupon(String couponName, String userName){

        //获取用户剩余优惠券数量
        Object obj = stringRedisTemplate.opsForHash().get("user", userName);
        //获取这个活动每个人可以抢什么
        String number1 = stringRedisTemplate.opsForValue().get("coupon:claimableQuantity:" + couponName);
        //获取剩余优惠券数量
        String number2 = stringRedisTemplate.opsForValue().get("coupon:CouponName:" + couponName);
        //活动是否过期
//        String time = stringRedisTemplate.opsForValue().get("coupon:CouponValidity:" + couponName);

        if (Objects.isNull(obj)){
            return R.error("用户不存在");
        }
        if (Objects.isNull(number1)){
            return R.error("优惠券不存在");
        }


        int num =  Integer.parseInt((String) obj);
        int nums1 = Integer.parseInt(number1);
        int num2 = Integer.parseInt(number2);
        if(num2 <= 0){
            return R.error("优惠券已领完");
        }
        if(num <= nums1){


            LambdaUpdateWrapper<Coupon> updateWrapper = new LambdaUpdateWrapper<>();
            int num3 = num2-1;
            updateWrapper.eq(Coupon::getCouponName, couponName).set(Coupon::getSurplusQuantity, num3);
            boolean update = couponService.update(updateWrapper);

            if (update){
                stringRedisTemplate.opsForValue().set("coupon:CouponName:"+couponName, String.valueOf(num3));
                Long userNum = stringRedisTemplate.opsForHash().increment("user", userName, 1);
                System.out.println(userNum);
            }


            LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Coupon::getCouponName, couponName);
            Coupon coupon = couponService.getOne(queryWrapper);
            System.out.println("------------------");
            System.out.println(coupon);
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getUsername, userName);
            User user = userService.getOne(wrapper);
            System.out.println("------------------");
            System.out.println(user);

            Log log = new Log();
            log.setCouponId(coupon.getId());
            log.setUserId(user.getId());
            log.setUseStatus("未使用");
            UUID uuid = UUID.randomUUID();
            long mostSignificantBits = uuid.getMostSignificantBits();
            log.setOrderId(mostSignificantBits);
            logService.save(log);

        }else{
            return R.error("每人最多领"+nums1+"张");
        }

        return R.ok();
    }

}
